﻿/* Project : MasterMind
 * 
 * Environment : .Net/WPF
 * 
 * Copyright (c) 2011 Clément Kawczak (mail@keiro.fr)
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Effects;

namespace MasterMind
{
    /// <summary>
    /// Logique d'interaction pour MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int[] tiSolution;
        private int[] tiCurrent;
        private SolidColorBrush[] tiColor;
        private int iCurrentLine;
        private int iColor;
        private SolidColorBrush SCBRec1;
        private SolidColorBrush SCBRec2;
        private SolidColorBrush SCBWhite;
        private SolidColorBrush SCBBlack;
        private SolidColorBrush SCBGrey;

        private Ellipse[] tEllipse;
        private Ellipse[] tEllipseG;
        private Rectangle[] tRec;

        public MainWindow()
        {
            InitializeComponent(); // Initialisation WPF de l'application
            Init();
        }

        // Initialisation des différents attributs de la classes
        void Init()
        {
            button1.ToolTip = "Valid the line";
            button2.ToolTip = "Quit MasterMind";
            button3.ToolTip = "Restart MasterMind";

            iColor = -1;

            // Quatre ellipses de la premiere ligne dropables 
            ellipse45.AllowDrop = true;
            ellipse46.AllowDrop = true;
            ellipse47.AllowDrop = true;
            ellipse48.AllowDrop = true;

            // Créer les références vers les objets graphiques
            tEllipse = new Ellipse[48];
            tEllipseG = new Ellipse[48];
            tRec = new Rectangle[12];
            InitObject();

            // Initialisation des couleurs utiles pou l'interface
            SCBRec1 = new SolidColorBrush();
            SCBRec1.Color = Color.FromRgb(255, 127, 39);
            SCBRec2 = new SolidColorBrush();
            SCBRec2.Color = Color.FromRgb(160, 121, 33);
            tRec[11].Fill = SCBRec1;
            SCBWhite = new SolidColorBrush();
            SCBWhite.Color = Color.FromRgb(255, 255, 255);
            SCBBlack = new SolidColorBrush();
            SCBBlack.Color = Color.FromRgb(0, 0, 0);
            SCBGrey = new SolidColorBrush();
            SCBGrey.Color = Color.FromRgb(131, 124, 124);

            // Initialisation des attributs de classes divers
            iCurrentLine = 12;
            tiCurrent = new int[4];
            for (int i = 0; i < 4; i++)
                tiCurrent[i] = -1;

            // Initialisation des couleurs de ellipse dragables
            // Rouge
            tiColor = new SolidColorBrush[6];
            SolidColorBrush red = new SolidColorBrush();
            red.Color = Color.FromRgb(255, 0, 0);
            tiColor[0] = red;
            // Vert
            SolidColorBrush green = new SolidColorBrush();
            green.Color = Color.FromRgb(0, 255, 0);
            tiColor[1] = green;
            // Bleu
            SolidColorBrush blue = new SolidColorBrush();
            blue.Color = Color.FromRgb(0, 0, 255);
            tiColor[2] = blue;
            // Marron
            SolidColorBrush brown = new SolidColorBrush();
            brown.Color = Color.FromRgb(101, 38, 19);
            tiColor[3] = brown;
            // Rose
            SolidColorBrush pink = new SolidColorBrush();
            pink.Color = Color.FromRgb(212, 54, 201);
            tiColor[4] = pink;
            // Jaune
            SolidColorBrush yellow = new SolidColorBrush();
            yellow.Color = Color.FromRgb(219, 235, 9);
            tiColor[5] = yellow;

            // Génération de la solution aléatoire
            tiSolution = new int[4];
            Random rnd = new Random();
            for (int i = 0; i < 4; i++)
            {
              tiSolution[i] = rnd.Next(0, 6);
            }
        }

        // Reference chaque objet graphique utile
        void InitObject()
        {
            // tEllipse contient les ellipses du centre (dropables)
            tEllipse[0] = ellipse1;
            tEllipse[1] = ellipse2;
            tEllipse[2] = ellipse3;
            tEllipse[3] = ellipse4;
            tEllipse[4] = ellipse5;
            tEllipse[5] = ellipse6;
            tEllipse[6] = ellipse7;
            tEllipse[7] = ellipse8;
            tEllipse[8] = ellipse9;
            tEllipse[9] = ellipse10;
            tEllipse[10] = ellipse11;
            tEllipse[11] = ellipse12;
            tEllipse[12] = ellipse13;
            tEllipse[13] = ellipse14;
            tEllipse[14] = ellipse15;
            tEllipse[15] = ellipse16;
            tEllipse[16] = ellipse17;
            tEllipse[17] = ellipse18;
            tEllipse[18] = ellipse19;
            tEllipse[19] = ellipse20;
            tEllipse[20] = ellipse21;
            tEllipse[21] = ellipse22;
            tEllipse[22] = ellipse23;
            tEllipse[23] = ellipse24;
            tEllipse[24] = ellipse25;
            tEllipse[25] = ellipse26;
            tEllipse[26] = ellipse27;
            tEllipse[27] = ellipse28;
            tEllipse[28] = ellipse29;
            tEllipse[29] = ellipse30;
            tEllipse[30] = ellipse31;
            tEllipse[31] = ellipse32;
            tEllipse[32] = ellipse33;
            tEllipse[33] = ellipse34;
            tEllipse[34] = ellipse35;
            tEllipse[35] = ellipse36;
            tEllipse[36] = ellipse37;
            tEllipse[37] = ellipse38;
            tEllipse[38] = ellipse39;
            tEllipse[39] = ellipse40;
            tEllipse[40] = ellipse41;
            tEllipse[41] = ellipse42;
            tEllipse[42] = ellipse43;
            tEllipse[43] = ellipse44;
            tEllipse[44] = ellipse45;
            tEllipse[45] = ellipse46;
            tEllipse[46] = ellipse47;
            tEllipse[47] = ellipse48;

            //tEllipseG contient toutes les ellipses de gauches (tips)
            tEllipseG[0] = ellipse1g;
            tEllipseG[1] = ellipse2g;
            tEllipseG[2] = ellipse3g;
            tEllipseG[3] = ellipse4g;
            tEllipseG[4] = ellipse5g;
            tEllipseG[5] = ellipse6g;
            tEllipseG[6] = ellipse7g;
            tEllipseG[7] = ellipse8g;
            tEllipseG[8] = ellipse9g;
            tEllipseG[9] = ellipse10g;
            tEllipseG[10] = ellipse11g;
            tEllipseG[11] = ellipse12g;
            tEllipseG[12] = ellipse13g;
            tEllipseG[13] = ellipse14g;
            tEllipseG[14] = ellipse15g;
            tEllipseG[15] = ellipse16g;
            tEllipseG[16] = ellipse17g;
            tEllipseG[17] = ellipse18g;
            tEllipseG[18] = ellipse19g;
            tEllipseG[19] = ellipse20g;
            tEllipseG[20] = ellipse21g;
            tEllipseG[21] = ellipse22g;
            tEllipseG[22] = ellipse23g;
            tEllipseG[23] = ellipse24g;
            tEllipseG[24] = ellipse25g;
            tEllipseG[25] = ellipse26g;
            tEllipseG[26] = ellipse27g;
            tEllipseG[27] = ellipse28g;
            tEllipseG[28] = ellipse29g;
            tEllipseG[29] = ellipse30g;
            tEllipseG[30] = ellipse31g;
            tEllipseG[31] = ellipse32g;
            tEllipseG[32] = ellipse33g;
            tEllipseG[33] = ellipse34g;
            tEllipseG[34] = ellipse35g;
            tEllipseG[35] = ellipse36g;
            tEllipseG[36] = ellipse37g;
            tEllipseG[37] = ellipse38g;
            tEllipseG[38] = ellipse39g;
            tEllipseG[39] = ellipse40g;
            tEllipseG[40] = ellipse41g;
            tEllipseG[41] = ellipse42g;
            tEllipseG[42] = ellipse43g;
            tEllipseG[43] = ellipse44g;
            tEllipseG[44] = ellipse45g;
            tEllipseG[45] = ellipse46g;
            tEllipseG[46] = ellipse47g;
            tEllipseG[47] = ellipse48g;

            // tRec contient tous les rectanges correspondants à des lignes
            tRec[0] = rectangle2;
            tRec[1] = rectangle3;
            tRec[2] = rectangle4;
            tRec[3] = rectangle5;
            tRec[4] = rectangle6;
            tRec[5] = rectangle7;
            tRec[6] = rectangle8;
            tRec[7] = rectangle9;
            tRec[8] = rectangle10;
            tRec[9] = rectangle11;
            tRec[10] = rectangle12;
            tRec[11] = rectangle13;
        }

        // Montre la solution cachée
        void ShowSolution()
        {
            ellipse127.Fill = tiColor[tiSolution[0]];
            ellipse128.Fill = tiColor[tiSolution[1]];
            ellipse129.Fill = tiColor[tiSolution[2]];
            ellipse130.Fill = tiColor[tiSolution[3]];
        }

        void Cheat()
        {
            textBlock1.Text = "Cheater !";
            textBlock2.Text = "Cheater !";
            textBlock3.Text = "Cheater !";
            textBlock4.Text = "Cheater !";
            textBlock5.Text = "Cheater !";
            textBlock6.Text = "Cheater !";
            textBlock7.Text = "Cheater !";
            textBlock8.Text = "Cheater !";
            textBlock9.Text = "Cheater !";
            textBlock10.Text = "Cheater !";
            textBlock11.Text = "Cheater !";
        }

        // Valid() est appelée lorsque le bouton "valid" est solicité
        void valid()
        {
            for (int i = 0; i < 4; i++)
            {
                if (tiCurrent[i] == -1)
                {
                    MessageBox.Show("Finish your turn before validate !");
                    return;
                }
            }
            bool win = true;
            for (int i = 0; i < 4; i++)
            {
                if (tiCurrent[i] != tiSolution[i])
                    win = false;
            }
            if (win)
            {
                MessageBox.Show("Congratulations, you have overcome the brain !");
                int cpt = (iCurrentLine - 1) * 4;
                for (int i = cpt; i < cpt + 4; i++)
                {
                    tEllipse[i].AllowDrop = false;
                }
                ShowTips();
                ShowSolution();
                button1.Visibility = System.Windows.Visibility.Hidden;
                return;
            }
            else
            {
                if (iCurrentLine != 1) // si ce n'est pas la dernière ligne
                {
                    ShowTips();
                    for (int i = 0; i < 4; i++) // reinitialisation du tab courant
                        tiCurrent[i] = -1;
                    int cpt = (iCurrentLine - 1) * 4;
                    tRec[iCurrentLine - 1].Fill = SCBRec2;
                    for (int i = cpt; i < cpt + 4; i++)
                    {
                        tEllipse[i].AllowDrop = false;
                    }
                    iCurrentLine -= 1;
                    tRec[iCurrentLine - 1].Fill = SCBRec1;
                    cpt = (iCurrentLine - 1) * 4;
                    for (int i = cpt; i < cpt + 4; i++)
                    {
                        tEllipse[i].AllowDrop = true;
                    }
                }
                else
                {
                    MessageBox.Show("Unfortunately, you lost...");
                    ShowSolution();
                    ShowTips();
                    button1.Visibility = System.Windows.Visibility.Hidden;
                    int cpt = (iCurrentLine - 1) * 4;
                    for (int i = cpt; i < cpt + 4; i++)
                    {
                        tEllipse[i].AllowDrop = false;
                    }
                    tRec[0].Fill = SCBRec2;
                }
            }
        }

        // ShowTips() est appelée pour remplir les ellipses de gauches afin d'aider le joueur
        void ShowTips()
        {
            Console.WriteLine("[" + toString(tiCurrent[0]) + ", " + toString(tiCurrent[1]) + ", " + toString(tiCurrent[2]) + ", " + toString(tiCurrent[3]) + "]");
            int[] tiCptCoul = new int[6];
            bool[] tiEverMade = new bool[4];
            for (int i = 0; i < 6; i++)
                tiCptCoul[i] = 0;

            int cptBlack = 0;
            int cptWhite = 3;

            for (int i = 0; i < 4; i++)
            {
                tiCptCoul[tiSolution[i]]++;
                tiEverMade[i] = false;
            }

            for (int i = 0; i < 4; i++)
            {
                if (tiCurrent[i] == tiSolution[i])
                {
                    // Bonne place
                    //tEllipseG[(iCurrentLine - 1) * 4 + i].Fill = SCBBlack;
                    tEllipseG[(iCurrentLine - 1) * 4 + cptBlack].Fill = SCBBlack;
                    cptBlack++;
                    tiCptCoul[tiSolution[i]]--;
                    tiEverMade[i] = true;
                }
            }

            for (int i = 0; i < 4; i++)
            {
                if (!tiEverMade[i] && tiCptCoul[tiCurrent[i]] != 0)
                {
                    // Mauvaise place
                    //tEllipseG[(iCurrentLine - 1) * 4 + i].Fill = SCBWhite;
                    tEllipseG[(iCurrentLine - 1) * 4 + cptWhite].Fill = SCBWhite;
                    cptWhite--;
                    tiCptCoul[tiCurrent[i]]--;
                }
            }
            //Si l'ellipse courante n'existe pas dans la solution, la couleur ne change pas
        }

        // Fonction de debug
        String toString(int n)
        {
            switch (n)
            {
                case 0:
                    return "rouge";
                case 1:
                    return "vert";
                case 2:
                    return "bleu";
                case 3:
                    return "marron";
                case 4:
                    return "rose";
                case 5:
                    return "jaune";
                default :
                    return "error";
            }
        }

        // Quitter le jeu
        void Quit()
        {
            string messageBoxText = "Do you want to quit MasterMind ?";
            string caption = "I can see my brain !";
            MessageBoxButton button = MessageBoxButton.YesNo;
            MessageBoxImage icon = MessageBoxImage.Warning;
            MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);
            if (result == MessageBoxResult.Yes)
                Application.Current.Shutdown();
        }

        // Cheat code and leave
        private void OnButtonKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.S)
            {
                ShowSolution();
                Cheat();
            }
            if (e.Key == Key.Escape)
                Quit();
        }

        // Curseur différent si element dragable
        private void MouseEnter(object sender, MouseEventArgs e)
        {
            this.Cursor = Cursors.Hand;
        }

        
        private void MouseLeave(object sender, MouseEventArgs e)
        {
            this.Cursor = null;
        }

        // Les Fonction suivantes correspondent à la mise en place du drag&drop, voir msdn pour plus d'info
        // Les fonctions concernées sont :
        // ellipse_MouseMove()
        // ellipse_DragEnter()
        // ellipse_DragOver()
        // ellipse_DragLeave()
        // ellipse_Drop()
        private void ellipse_MouseMove(object sender, MouseEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;

            if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
            {
                DragDrop.DoDragDrop(ellipse, ellipse.Fill.ToString(), DragDropEffects.Copy);
            }
        }

        private Brush _previousFill = null;

        private void ellipse_DragEnter(object sender, DragEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;
            if (ellipse != null)
            {
                // Save the current Fill brush so that you can revert back to this value in DragLeave.
                _previousFill = ellipse.Fill;

                // If the DataObject contains string data, extract it.
                if (e.Data.GetDataPresent(DataFormats.StringFormat))
                {
                    string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

                    // If the string can be converted into a Brush, convert it.
                    BrushConverter converter = new BrushConverter();
                }
            }
        }

        private void ellipse_DragOver(object sender, DragEventArgs e)
        {

                e.Effects = DragDropEffects.Move;

                // If the DataObject contains string data, extract it.
                if (e.Data.GetDataPresent(DataFormats.StringFormat))
                {
                    string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

                    // If the string can be converted into a Brush, allow copying.
                    BrushConverter converter = new BrushConverter();
                    if (converter.IsValid(dataString))
                    {
                        e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
                    }
                }
        }

        private void ellipse_DragLeave(object sender, DragEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;
            if (ellipse != null)
            {
                ellipse.Fill = _previousFill;
            }
        }

        private void ellipse_Drop(object sender, DragEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;
            if (ellipse != null)
            {
                // If the DataObject contains string data, extract it.
                if (e.Data.GetDataPresent(DataFormats.StringFormat))
                {
                    string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

                    // If the string can be converted into a Brush, 
                    // convert it and apply it to the ellipse.
                    BrushConverter converter = new BrushConverter();
                    if (converter.IsValid(dataString))
                    {
                        Brush newFill = (Brush)converter.ConvertFromString(dataString);
                        ellipse.Fill = newFill;
                        int color = 0;
                        for (int i = 0; i < 6; i++)
                        {
                            if(newFill.ToString() == tiColor[i].ToString())
                                color = i;
                        }
                        Console.WriteLine(((int)ellipse.GetValue(Grid.ColumnProperty)) - 2 + " | " + toString(color));
                        tiCurrent[((int)ellipse.GetValue(Grid.ColumnProperty)) - 2] = color;
                    }
                }
            }
        }

        // Reinitialise le jeu
        void Restart()
        {
            textBlock1.Text = "";
            textBlock2.Text = "";
            textBlock3.Text = "";
            textBlock4.Text = "";
            textBlock5.Text = "";
            textBlock6.Text = "";
            textBlock7.Text = "";
            textBlock8.Text = "";
            textBlock9.Text = "";
            textBlock10.Text = "";
            textBlock11.Text = "";

            for (int i = 0; i < 48; i++)
            {
                tEllipse[i].Fill = SCBBlack;
                tEllipseG[i].Fill = SCBGrey;
            }

            for (int i = 0; i < 4; i++) // reinitialisation du tab courant
                tiCurrent[i] = -1;
            int cpt = (iCurrentLine - 1) * 4;
            tRec[iCurrentLine - 1].Fill = SCBRec2;
            for (int i = cpt; i < cpt + 4; i++)
            {
                tEllipse[i].AllowDrop = false;
            }

            iCurrentLine = 12;
            tiCurrent = new int[4];
            for (int i = 0; i < 4; i++)
                tiCurrent[i] = -1;

            tRec[iCurrentLine - 1].Fill = SCBRec1;

            ellipse45.AllowDrop = true;
            ellipse46.AllowDrop = true;
            ellipse47.AllowDrop = true;
            ellipse48.AllowDrop = true;

            ellipse127.Fill = SCBGrey;
            ellipse128.Fill = SCBGrey;
            ellipse129.Fill = SCBGrey;
            ellipse130.Fill = SCBGrey;

            Random rnd = new Random();
            for (int i = 0; i < 4; i++)
            {
                tiSolution[i] = rnd.Next(0, 6);
            }

            button1.Visibility = System.Windows.Visibility.Visible;
        }

        // Evenement du bouton 1 (valid)
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            valid();
        }

        // Evenement du bouton 2 (leave)
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Quit();
        }

        // Evenement du bouton 3 (restart)
        private void button3_Click(object sender, RoutedEventArgs e)
        {
            string messageBoxText = "Do you want to restart MasterMind ?";
            string caption = "I can see my brain !";
            MessageBoxButton button = MessageBoxButton.YesNo;
            MessageBoxImage icon = MessageBoxImage.Warning;
            MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);
            if (result == MessageBoxResult.Yes)
                Restart();
        }

        // click_1() et click_2() servent à définir les couleurs par un simple click
        private void click_1(object sender, MouseButtonEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;
            if (ellipse == ellipse121)
                iColor = 0;
            else if (ellipse == ellipse122)
                iColor = 1;
            else if (ellipse == ellipse123)
                iColor = 2;
            else if (ellipse == ellipse124)
                iColor = 3;
            else if (ellipse == ellipse125)
                iColor = 4;
            else if (ellipse == ellipse126)
                iColor = 5;
        }

        private void click_2(object sender, MouseButtonEventArgs e)
        {
            Ellipse ellipse = sender as Ellipse;
            if (iColor != -1 && ellipse.AllowDrop)
            {
                ellipse.Fill = tiColor[iColor];
                tiCurrent[((int)ellipse.GetValue(Grid.ColumnProperty)) - 2] = iColor;
            }     
        }

    }
}
